/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年9月5日
 * 项目： rainhy-webcore
 */
package com.rainhy.config.interceptor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.rainhy.config.config.ConfigProperty;
import com.rainhy.config.context.ConfigContext;
import com.rainhy.core.util.AssertUtils;
import com.rainhy.core.util.RainhyUtils;

/**
 * springmvc 拦截器<br>
 * 向页面注入"config"中配置过的值<br>
 * <b style="color:red;">注意:如果在 key 中包含特殊字符,则全部自动转换成"_"</b>
 * 
 * @author rain
 * @version [版本号, 2016年9月5日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class ConfigHandlerInterceptor extends HandlerInterceptorAdapter implements InitializingBean {
    
    /** 日志 */
    private static final Logger logger = LoggerFactory.getLogger(ConfigHandlerInterceptor.class);
    
    /** 遇到特殊字符,进行替换的字符 */
    private static final char REPLACEMENT = '_';
    
    /** 是否覆盖原始值 */
    private boolean isCover = true;
    
    /** 排除的配置key,多个key用","分割开 */
    private String excludeConfigKey;
    
    /** 包含的配置key,多个key用","分割开 */
    private String includeConfigKey;
    
    /** 所有包含的key:配置项中的key;value:向页面注入的key */
    private Map<String, String> includeConfigKeyMap = new HashMap<>();
    
    @Override
    public void afterPropertiesSet() throws Exception {
        ConfigContext context = ConfigContext.getContext();
        
        AssertUtils.notNull(context, "请初始化ConfigContext");
        
        Set<String> includeConfigKeys = new HashSet<>();
        if (StringUtils.isNotBlank(includeConfigKey)) { // 优先判断"包含的配置key"
            String[] split = StringUtils.split(includeConfigKey, ",");
            includeConfigKeys.addAll(Arrays.asList(split));
        }
        
        if (CollectionUtils.isEmpty(includeConfigKeys)) {   // 如果"包含的配置key"为空,则直接从 ConfigContext 里面取 key
            Map<String, ConfigProperty> allConfigPropertyMap = context.getAllConfigPropertyMap();
            includeConfigKeys.addAll(allConfigPropertyMap.keySet());
        }
        
        if (StringUtils.isNotBlank(excludeConfigKey)) {   // 去掉"排除的配置key"
            String[] split = StringUtils.split(excludeConfigKey, ",");
            includeConfigKeys.removeAll(Arrays.asList(split));
        }
        
        List<String> list = new ArrayList<>(includeConfigKeys);
        Collections.sort(list);
        for (String key : list) {
            AssertUtils.isTrue(context.contains(key), "在配置容器中,不存在key:{}", key);
            String key2 = RainhyUtils.replaceSpecialCharacter(key, REPLACEMENT);
            this.includeConfigKeyMap.put(key, key2);
            logger.debug("     向页面注入配置项[key: {}]", key2);
        }
    }
    
    /** 排除的配置key,多个key用","分割开 */
    public String getExcludeConfigKey() {
        return excludeConfigKey;
    }
    
    /** 包含的配置key,多个key用","分割开 */
    public String getIncludeConfigKey() {
        return includeConfigKey;
    }
    
    /** 是否覆盖原始值 */
    public boolean isCover() {
        return isCover;
    }
    
    @Override
    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {
        if (MapUtils.isNotEmpty(this.includeConfigKeyMap)) {
            if (this.isCover) {   // 覆盖
                for (Map.Entry<String, String> entry : includeConfigKeyMap.entrySet()) {
                    request.setAttribute(entry.getValue(), ConfigContext.getValue(entry.getKey()));
                }
            } else {    // 不覆盖已经存在的值
                for (Map.Entry<String, String> entry : includeConfigKeyMap.entrySet()) {
                    Object attribute = request.getAttribute(entry.getValue());
                    if (attribute == null) {
                        request.setAttribute(entry.getValue(), ConfigContext.getValue(entry.getKey()));
                    }
                }
            }
        }
        return true;
    }
    
    /** 是否覆盖原始值 */
    public void setCover(boolean isCover) {
        this.isCover = isCover;
    }
    
    /** 排除的配置key,多个key用","分割开 */
    public void setExcludeConfigKey(String excludeConfigKey) {
        this.excludeConfigKey = excludeConfigKey;
    }
    
    /** 包含的配置key,多个key用","分割开 */
    public void setIncludeConfigKey(String includeConfigKey) {
        this.includeConfigKey = includeConfigKey;
    }
}
